﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.ServiceModel;
using System.ServiceModel.Activation;

using Cookbook.Services.Core.Commanding;
using Cookbook.Services.Core.Common;
using Cookbook.Services.Host.ExceptionHandling;

namespace Cookbook.Services.Host
{
    [ServiceContract(Namespace = "http://www.dennisdoomen.net/commandservice/v1.0")]
    [ServiceKnownType("GetKnownTypes")]
    [ExceptionShieldingBehavior]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class CommandService
    {
        private static readonly ILogger logger = new EntLibLogger();
        private readonly BatchedCommandExecutor executor;

        public CommandService(BatchedCommandExecutor executor)
        {
            this.executor = executor;
        }

        /// <summary>
        ///   Buildup each command with the unityContainer and execute the command
        /// </summary>
        /// <param name = "commands">The commands.</param>
        [OperationContract]
        [FaultContract(typeof (ApplicationErrorFault))]
        [FaultContract(typeof (RuleViolationFault))]
        public void Execute(IEnumerable<Command> commands)
        {
            PrincipleHelper.EnsureCurrentPrincipal();

            executor.Execute(commands.ToArray());
        }

        /// <summary>
        ///   Return all ServiceCommands available in the current assembly.
        /// </summary>
        /// <param name = "provider"></param>
        /// <returns></returns>
        public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider)
        {
            IEnumerable<Type> query =
                from type in typeof (Command).Assembly.GetTypes()
                where typeof (Command).IsAssignableFrom(type)
                select type;

            return query.ToArray();
        }

        [OperationContract]
        public void ProcessClientError(string[] errorLines)
        {
            PrincipleHelper.EnsureCurrentPrincipal();

            foreach (var errorLine in errorLines)
            {
                logger.Error(errorLine);
            }

            logger.Error("");
        }
    }
}